package io.gitee.zhangbinhub.admin.log.service

import com.mybatisflex.core.BaseMapper
import com.mybatisflex.core.query.QueryChain
import com.mybatisflex.core.query.QueryWrapper
import com.mybatisflex.core.util.LambdaGetter
import io.gitee.zhangbinhub.acp.boot.log.LogAdapter
import io.gitee.zhangbinhub.acp.core.common.CalendarTools
import io.gitee.zhangbinhub.admin.common.po.QueryParam
import io.gitee.zhangbinhub.admin.log.base.BaseService
import io.gitee.zhangbinhub.admin.log.constant.LogConstant
import io.gitee.zhangbinhub.admin.log.entity.*
import io.gitee.zhangbinhub.admin.log.mapper.LoginLogMapper
import io.gitee.zhangbinhub.admin.log.mapper.OperateLogMapper
import io.gitee.zhangbinhub.admin.log.mapper.RouteLogMapper
import io.gitee.zhangbinhub.admin.log.repo.*
import org.noear.solon.annotation.Component
import org.noear.solon.data.annotation.Transaction

/**
 * @since JDK 11
 */
@Component
open class LogHistoryService(
    private val logAdapter: LogAdapter,
    private val routeLogRepository: RouteLogRepository,
    private val operateLogRepository: OperateLogRepository,
    private val loginLogRepository: LoginLogRepository,
    private val routeLogHistoryRepository: RouteLogHistoryRepository,
    private val operateLogHistoryRepository: OperateLogHistoryRepository,
    private val loginLogHistoryRepository: LoginLogHistoryRepository
) : BaseService() {

    private fun <T> buildQueryChain(
        baseMapper: BaseMapper<T>,
        requestTimeGetter: LambdaGetter<T>,
        timeBegin: Long
    ): QueryChain<T> =
        QueryChain.of(baseMapper).where(requestTimeGetter).le(timeBegin)

    private fun buildQueryParam(quantityPerProcess: Int): QueryParam =
        QueryParam().apply {
            this.currPage = 1
            this.pageSize = quantityPerProcess
            this.orderName = "requestTime"
            this.orderCommand = "asc"
        }

    @Transaction
    fun doRouteLogHistory(timeBegin: Long, quantityPerProcess: Int): Int {
        logAdapter.info("开始执行：路由日志迁移至历史库")
        return doPageQuery(
            buildQueryParam(quantityPerProcess),
            buildQueryChain(routeLogRepository, RouteLog::getRequestTime, timeBegin)
        ).let { pageVo ->
            logAdapter.info("本次处理${pageVo.content.size}条路由日志")
            if (pageVo.content.isNotEmpty()) {
                pageVo.content.map { RouteLogMapper.INSTANCE.toHistory(it) }.let {
                    routeLogHistoryRepository.insertBatch(it)
                }
                pageVo.content.map { it.id }.let {
                    routeLogRepository.deleteBatchByIds(it)
                }
                if (pageVo.content.isEmpty()) {
                    logAdapter.info("路由日志迁移完成")
                }
            }
            pageVo.content.size
        }
    }

    @Transaction
    fun doDeleteRouteLogHistory(time: Long) {
        logAdapter.info("开始清理历史路由日志...")
        routeLogHistoryRepository.deleteByQuery(QueryWrapper.create().where(RouteLogHistory::getRequestTime).lt(time))
        logAdapter.info("历史路由日志清理完成")
    }

    @Transaction
    fun doOperateLogHistory(timeBegin: Long, quantityPerProcess: Int): Int {
        logAdapter.info("开始执行：操作日志迁移至历史库")
        return doPageQuery(
            buildQueryParam(quantityPerProcess),
            buildQueryChain(operateLogRepository, OperateLog::getRequestTime, timeBegin)
        ).let { pageVo ->
            logAdapter.info("本次处理${pageVo.content.size}条操作日志")
            if (pageVo.content.isNotEmpty()) {
                pageVo.content.map { OperateLogMapper.INSTANCE.toHistory(it) }.let {
                    operateLogHistoryRepository.insertBatch(it)
                }
                pageVo.content.map { it.id }.let {
                    operateLogRepository.deleteBatchByIds(it)
                }
                if (pageVo.content.isEmpty()) {
                    logAdapter.info("操作日志迁移完成")
                }
            }
            pageVo.content.size
        }
    }

    @Transaction
    fun doDeleteOperateLogHistory(time: Long) {
        logAdapter.info("开始清理历史操作日志...")
        operateLogHistoryRepository.deleteByQuery(
            QueryWrapper.create().where(OperateLogHistory::getRequestTime).lt(time)
        )
        logAdapter.info("历史操作日志清理完成")
    }

    @Transaction
    fun doLoginLogHistory(timeBegin: Long, quantityPerProcess: Int): Int {
        logAdapter.info("开始执行：登录日志迁移至历史库")
        return doPageQuery(
            buildQueryParam(quantityPerProcess),
            buildQueryChain(loginLogRepository, LoginLog::getRequestTime, timeBegin)
        ).let { pageVo ->
            logAdapter.info("本次处理${pageVo.content.size}条登录日志")
            if (pageVo.content.isNotEmpty()) {
                pageVo.content.map { LoginLogMapper.INSTANCE.toHistory(it) }.let {
                    loginLogHistoryRepository.insertBatch(it)
                }
                pageVo.content.map { it.id }.let {
                    loginLogRepository.deleteBatchByIds(it)
                }
                if (pageVo.content.isEmpty()) {
                    logAdapter.info("登录日志迁移完成")
                }
            }
            pageVo.content.size
        }
    }

    @Transaction
    fun doDeleteLoginLogHistory(time: Long) {
        logAdapter.info("开始清理历史登录日志...")
        CalendarTools.getNowDateTime().withTimeAtStartOfDay()
            .minusMonths(LogConstant.LOGIN_LOG_STATISTICS_MAX_MONTH).millis.also {
                if (it < time) {
                    loginLogHistoryRepository.deleteByQuery(
                        QueryWrapper.create().where(LoginLogHistory::getRequestTime).lt(it)
                    )
                } else {
                    loginLogHistoryRepository.deleteByQuery(
                        QueryWrapper.create().where(LoginLogHistory::getRequestTime).lt(time)
                    )
                }
            }
        logAdapter.info("历史登录日志清理完成")
    }
}